{
    "cells": [
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "6d742657-8e6a-439d-a65a-3c76e73c8810",
            "metadata": {},
            "source": [
                "# SS GLM "
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "5ddc86c8",
            "metadata": {},
            "source": [
                ">The following codes are demos only. It's **NOT for production** due to system security concerns, please **DO NOT** use it directly in production.\n"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "629aad7f",
            "metadata": {},
            "source": [
                "## Train a model with sklearn "
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "d9774618-798e-421f-9be0-4fb954d7c710",
            "metadata": {},
            "source": [
                "Replicate the same experiment from sklearn [tutorial](https://scikit-learn.org/stable/auto_examples/linear_model/plot_tweedie_regression_insurance_claims) on insurance claims using sf ss glm."
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 1,
            "id": "364a380e-9cea-42e3-8ab5-06635df97478",
            "metadata": {
                "tags": []
            },
            "outputs": [],
            "source": [
                "import matplotlib.pyplot as plt\n",
                "import numpy as np\n",
                "import pandas as pd\n",
                "\n",
                "from functools import partial\n",
                "from sklearn.datasets import fetch_openml\n",
                "from sklearn.metrics import (\n",
                "    mean_absolute_error,\n",
                "    mean_squared_error,\n",
                "    mean_tweedie_deviance,\n",
                ")\n",
                "\n",
                "\n",
                "def load_mtpl2(n_samples=None):\n",
                "    \"\"\"Fetch the French Motor Third-Party Liability Claims dataset.\n",
                "\n",
                "    Parameters\n",
                "    ----------\n",
                "    n_samples: int, default=None\n",
                "      number of samples to select (for faster run time). Full dataset has\n",
                "      678013 samples.\n",
                "    \"\"\"\n",
                "    # freMTPL2freq dataset from https://www.openml.org/d/41214\n",
                "    df_freq = fetch_openml(data_id=41214, as_frame=True).data\n",
                "    df_freq[\"IDpol\"] = df_freq[\"IDpol\"].astype(int)\n",
                "    df_freq.set_index(\"IDpol\", inplace=True)\n",
                "\n",
                "    # freMTPL2sev dataset from https://www.openml.org/d/41215\n",
                "    df_sev = fetch_openml(data_id=41215, as_frame=True).data\n",
                "\n",
                "    # sum ClaimAmount over identical IDs\n",
                "    df_sev = df_sev.groupby(\"IDpol\").sum()\n",
                "\n",
                "    df = df_freq.join(df_sev, how=\"left\")\n",
                "    df[\"ClaimAmount\"].fillna(0, inplace=True)\n",
                "\n",
                "    # unquote string fields\n",
                "    for column_name in df.columns[df.dtypes.values == object]:\n",
                "        df[column_name] = df[column_name].str.strip(\"'\")\n",
                "    return df.iloc[:n_samples]\n",
                "\n",
                "\n",
                "def plot_obs_pred(\n",
                "    df,\n",
                "    feature,\n",
                "    weight,\n",
                "    observed,\n",
                "    predicted,\n",
                "    y_label=None,\n",
                "    title=None,\n",
                "    ax=None,\n",
                "    fill_legend=False,\n",
                "):\n",
                "    \"\"\"Plot observed and predicted - aggregated per feature level.\n",
                "\n",
                "    Parameters\n",
                "    ----------\n",
                "    df : DataFrame\n",
                "        input data\n",
                "    feature: str\n",
                "        a column name of df for the feature to be plotted\n",
                "    weight : str\n",
                "        column name of df with the values of weights or exposure\n",
                "    observed : str\n",
                "        a column name of df with the observed target\n",
                "    predicted : DataFrame\n",
                "        a dataframe, with the same index as df, with the predicted target\n",
                "    fill_legend : bool, default=False\n",
                "        whether to show fill_between legend\n",
                "    \"\"\"\n",
                "    # aggregate observed and predicted variables by feature level\n",
                "    df_ = df.loc[:, [feature, weight]].copy()\n",
                "    df_[\"observed\"] = df[observed] * df[weight]\n",
                "    df_[\"predicted\"] = predicted * df[weight]\n",
                "    df_ = (\n",
                "        df_.groupby([feature])[[weight, \"observed\", \"predicted\"]]\n",
                "        .sum()\n",
                "        .assign(observed=lambda x: x[\"observed\"] / x[weight])\n",
                "        .assign(predicted=lambda x: x[\"predicted\"] / x[weight])\n",
                "    )\n",
                "\n",
                "    ax = df_.loc[:, [\"observed\", \"predicted\"]].plot(style=\".\", ax=ax)\n",
                "    y_max = df_.loc[:, [\"observed\", \"predicted\"]].values.max() * 0.8\n",
                "    p2 = ax.fill_between(\n",
                "        df_.index,\n",
                "        0,\n",
                "        y_max * df_[weight] / df_[weight].values.max(),\n",
                "        color=\"g\",\n",
                "        alpha=0.1,\n",
                "    )\n",
                "    if fill_legend:\n",
                "        ax.legend([p2], [\"{} distribution\".format(feature)])\n",
                "    ax.set(\n",
                "        ylabel=y_label if y_label is not None else None,\n",
                "        title=title if title is not None else \"Train: Observed vs Predicted\",\n",
                "    )\n",
                "\n",
                "\n",
                "def score_estimator(\n",
                "    estimator,\n",
                "    X_train,\n",
                "    X_test,\n",
                "    df_train,\n",
                "    df_test,\n",
                "    target,\n",
                "    weights,\n",
                "    tweedie_powers=None,\n",
                "):\n",
                "    \"\"\"Evaluate an estimator on train and test sets with different metrics\"\"\"\n",
                "\n",
                "    metrics = [\n",
                "        (\"D² explained\", None),  # Use default scorer if it exists\n",
                "        (\"mean abs. error\", mean_absolute_error),\n",
                "        (\"mean squared error\", mean_squared_error),\n",
                "    ]\n",
                "    if tweedie_powers:\n",
                "        metrics += [\n",
                "            (\n",
                "                \"mean Tweedie dev p={:.4f}\".format(power),\n",
                "                partial(mean_tweedie_deviance, power=power),\n",
                "            )\n",
                "            for power in tweedie_powers\n",
                "        ]\n",
                "\n",
                "    res = []\n",
                "    for subset_label, X, df in [\n",
                "        (\"train\", X_train, df_train),\n",
                "        (\"test\", X_test, df_test),\n",
                "    ]:\n",
                "        y, _weights = df[target], df[weights]\n",
                "        for score_label, metric in metrics:\n",
                "            if isinstance(estimator, tuple) and len(estimator) == 2:\n",
                "                # Score the model consisting of the product of frequency and\n",
                "                # severity models.\n",
                "                est_freq, est_sev = estimator\n",
                "                y_pred = est_freq.predict(X) * est_sev.predict(X)\n",
                "            else:\n",
                "                y_pred = estimator.predict(X)\n",
                "\n",
                "            if metric is None:\n",
                "                if not hasattr(estimator, \"score\"):\n",
                "                    continue\n",
                "                score = estimator.score(X, y, sample_weight=_weights)\n",
                "            else:\n",
                "                score = metric(y, y_pred, sample_weight=_weights)\n",
                "\n",
                "            res.append({\"subset\": subset_label, \"metric\": score_label, \"score\": score})\n",
                "\n",
                "    res = (\n",
                "        pd.DataFrame(res)\n",
                "        .set_index([\"metric\", \"subset\"])\n",
                "        .score.unstack(-1)\n",
                "        .round(4)\n",
                "        .loc[:, [\"train\", \"test\"]]\n",
                "    )\n",
                "    return res"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 2,
            "id": "7e58adee",
            "metadata": {},
            "outputs": [
                {
                    "name": "stderr",
                    "output_type": "stream",
                    "text": [
                        "/home/zoupeicheng.zpc/miniconda3/envs/py38/lib/python3.8/site-packages/sklearn/datasets/_openml.py:1022: FutureWarning: The default value of `parser` will change from `'liac-arff'` to `'auto'` in 1.4. You can set `parser='auto'` to silence this warning. Therefore, an `ImportError` will be raised from 1.4 if the dataset is dense and pandas is not installed. Note that the pandas parser may return different data types. See the Notes Section in fetch_openml's API doc for details.\n",
                        "  warn(\n",
                        "/home/zoupeicheng.zpc/miniconda3/envs/py38/lib/python3.8/site-packages/sklearn/datasets/_openml.py:1022: FutureWarning: The default value of `parser` will change from `'liac-arff'` to `'auto'` in 1.4. You can set `parser='auto'` to silence this warning. Therefore, an `ImportError` will be raised from 1.4 if the dataset is dense and pandas is not installed. Note that the pandas parser may return different data types. See the Notes Section in fetch_openml's API doc for details.\n",
                        "  warn(\n"
                    ]
                },
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "       ClaimNb  Exposure Area  VehPower  VehAge  DrivAge  BonusMalus VehBrand  \\\n",
                        "IDpol                                                                           \n",
                        "139.0      1.0      0.75    F       7.0     1.0     61.0        50.0      B12   \n",
                        "190.0      1.0      0.14    B      12.0     5.0     50.0        60.0      B12   \n",
                        "414.0      1.0      0.14    E       4.0     0.0     36.0        85.0      B12   \n",
                        "424.0      2.0      0.62    F      10.0     0.0     51.0       100.0      B12   \n",
                        "463.0      1.0      0.31    A       5.0     0.0     45.0        50.0      B12   \n",
                        "\n",
                        "        VehGas  Density Region  ClaimAmount   PurePremium  Frequency  \\\n",
                        "IDpol                                                                  \n",
                        "139.0  Regular  27000.0    R11       303.00    404.000000   1.333333   \n",
                        "190.0   Diesel     56.0    R25      1981.84  14156.000000   7.142857   \n",
                        "414.0  Regular   4792.0    R11      1456.55  10403.928571   7.142857   \n",
                        "424.0  Regular  27000.0    R11     10834.00  17474.193548   3.225806   \n",
                        "463.0  Regular     12.0    R73      3986.67  12860.225806   3.225806   \n",
                        "\n",
                        "       AvgClaimAmount  \n",
                        "IDpol                  \n",
                        "139.0          303.00  \n",
                        "190.0         1981.84  \n",
                        "414.0         1456.55  \n",
                        "424.0         5417.00  \n",
                        "463.0         3986.67  \n"
                    ]
                }
            ],
            "source": [
                "from sklearn.compose import ColumnTransformer\n",
                "from sklearn.pipeline import make_pipeline\n",
                "from sklearn.preprocessing import (\n",
                "    FunctionTransformer,\n",
                "    KBinsDiscretizer,\n",
                "    OneHotEncoder,\n",
                "    StandardScaler,\n",
                ")\n",
                "\n",
                "df = load_mtpl2()\n",
                "\n",
                "# Note: filter out claims with zero amount, as the severity model\n",
                "# requires strictly positive target values.\n",
                "df.loc[(df[\"ClaimAmount\"] == 0) & (df[\"ClaimNb\"] >= 1), \"ClaimNb\"] = 0\n",
                "\n",
                "# Correct for unreasonable observations (that might be data error)\n",
                "# and a few exceptionally large claim amounts\n",
                "df[\"ClaimNb\"] = df[\"ClaimNb\"].clip(upper=4)\n",
                "df[\"Exposure\"] = df[\"Exposure\"].clip(upper=1)\n",
                "df[\"ClaimAmount\"] = df[\"ClaimAmount\"].clip(upper=200000)\n",
                "\n",
                "log_scale_transformer = make_pipeline(\n",
                "    FunctionTransformer(func=np.log), StandardScaler()\n",
                ")\n",
                "\n",
                "column_trans = ColumnTransformer(\n",
                "    [\n",
                "        (\n",
                "            \"binned_numeric\",\n",
                "            KBinsDiscretizer(n_bins=10, subsample=int(2e5), random_state=0),\n",
                "            [\"VehAge\", \"DrivAge\"],\n",
                "        ),\n",
                "        (\n",
                "            \"onehot_categorical\",\n",
                "            OneHotEncoder(),\n",
                "            [\"VehBrand\", \"VehPower\", \"VehGas\", \"Region\", \"Area\"],\n",
                "        ),\n",
                "        (\"passthrough_numeric\", \"passthrough\", [\"BonusMalus\"]),\n",
                "        (\"log_scaled_numeric\", log_scale_transformer, [\"Density\"]),\n",
                "    ],\n",
                "    remainder=\"drop\",\n",
                ")\n",
                "X = column_trans.fit_transform(df)\n",
                "\n",
                "# Insurances companies are interested in modeling the Pure Premium, that is\n",
                "# the expected total claim amount per unit of exposure for each policyholder\n",
                "# in their portfolio:\n",
                "df[\"PurePremium\"] = df[\"ClaimAmount\"] / df[\"Exposure\"]\n",
                "\n",
                "# This can be indirectly approximated by a 2-step modeling: the product of the\n",
                "# Frequency times the average claim amount per claim:\n",
                "df[\"Frequency\"] = df[\"ClaimNb\"] / df[\"Exposure\"]\n",
                "df[\"AvgClaimAmount\"] = df[\"ClaimAmount\"] / np.fmax(df[\"ClaimNb\"], 1)\n",
                "\n",
                "with pd.option_context(\"display.max_columns\", 15):\n",
                "    print(df[df.ClaimAmount > 0].head())"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 3,
            "id": "8d570ce5",
            "metadata": {},
            "outputs": [],
            "source": [
                "from sklearn.model_selection import train_test_split\n",
                "\n",
                "df_train, df_test, X_train, X_test = train_test_split(df, X, random_state=0)"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "id": "fb400b1f-f516-4348-8812-e05a2e8f5e17",
            "metadata": {
                "tags": []
            },
            "source": [
                "### Fit the GLM model (tweedie)\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 4,
            "id": "0ffb9d32-4150-41cb-a6e9-65cbccf6568a",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Evaluation of the Product Model and the Tweedie Regressor on target PurePremium\n",
                        "                                      T              \n",
                        "subset                            train          test\n",
                        "metric                                               \n",
                        "D² explained               1.690000e-02  1.420000e-02\n",
                        "mean Tweedie dev p=1.5000  7.640770e+01  7.640880e+01\n",
                        "mean Tweedie dev p=1.7000  3.682880e+01  3.692270e+01\n",
                        "mean Tweedie dev p=1.8000  3.037600e+01  3.045390e+01\n",
                        "mean Tweedie dev p=1.9000  3.382120e+01  3.387830e+01\n",
                        "mean Tweedie dev p=1.9900  2.015347e+02  2.015587e+02\n",
                        "mean Tweedie dev p=1.9990  1.914538e+03  1.914387e+03\n",
                        "mean Tweedie dev p=1.9999  1.904747e+04  1.904558e+04\n",
                        "mean abs. error            2.739865e+02  2.731249e+02\n",
                        "mean squared error         3.295505e+07  3.213056e+07\n"
                    ]
                }
            ],
            "source": [
                "from sklearn.linear_model import TweedieRegressor\n",
                "\n",
                "glm_pure_premium = TweedieRegressor(power=1.9, alpha=0.1, solver='newton-cholesky')\n",
                "glm_pure_premium.fit(\n",
                "    X_train, df_train[\"PurePremium\"], sample_weight=df_train[\"Exposure\"]\n",
                ")\n",
                "\n",
                "tweedie_powers = [1.5, 1.7, 1.8, 1.9, 1.99, 1.999, 1.9999]\n",
                "\n",
                "scores_glm_pure_premium = score_estimator(\n",
                "    glm_pure_premium,\n",
                "    X_train,\n",
                "    X_test,\n",
                "    df_train,\n",
                "    df_test,\n",
                "    target=\"PurePremium\",\n",
                "    weights=\"Exposure\",\n",
                "    tweedie_powers=tweedie_powers,\n",
                ")\n",
                "\n",
                "scores = pd.concat(\n",
                "    [scores_glm_pure_premium],\n",
                "    axis=1,\n",
                "    sort=True,\n",
                "    keys=(\"TweedieRegressor\"),\n",
                ")\n",
                "print(\"Evaluation of the Product Model and the Tweedie Regressor on target PurePremium\")\n",
                "with pd.option_context(\"display.expand_frame_repr\", False):\n",
                "    print(scores)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 5,
            "id": "2cd54470",
            "metadata": {},
            "outputs": [],
            "source": [
                "n_iter = glm_pure_premium.n_iter_"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "d809add7",
            "metadata": {},
            "source": [
                "### Fit the SS GLM model (tweedie)\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 6,
            "id": "c0f1fe19",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "The version of SecretFlow: 1.4.0.dev20240130\n"
                    ]
                },
                {
                    "name": "stderr",
                    "output_type": "stream",
                    "text": [
                        "2024-02-19 14:19:08,097\tINFO worker.py:1538 -- Started a local Ray instance.\n"
                    ]
                }
            ],
            "source": [
                "import secretflow as sf\n",
                "\n",
                "# Check the version of your SecretFlow\n",
                "print('The version of SecretFlow: {}'.format(sf.__version__))\n",
                "\n",
                "# In case you have a running secretflow runtime already.\n",
                "sf.shutdown()\n",
                "\n",
                "sf.init(['alice', 'bob'], address='local')\n",
                "\n",
                "alice, bob = sf.PYU('alice'), sf.PYU('bob')\n",
                "spu = sf.SPU(\n",
                "    sf.utils.testing.cluster_def(\n",
                "        ['alice', 'bob'],\n",
                "        {\"protocol\": \"REF2K\", \"field\": \"FM128\", \"fxp_fraction_bits\": 40},\n",
                "    ),\n",
                ")"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 7,
            "id": "dee30156",
            "metadata": {},
            "outputs": [],
            "source": [
                "from secretflow.data import FedNdarray, PartitionWay\n",
                "\n",
                "x, y = X_train, df_train[\"PurePremium\"]\n",
                "w = df_train[\"Exposure\"]\n",
                "\n",
                "\n",
                "def x_to_vdata(x):\n",
                "    x = x.todense()\n",
                "    v_data = FedNdarray(\n",
                "        partitions={\n",
                "            alice: alice(lambda: x[:, :15])(),\n",
                "            bob: bob(lambda: x[:, 15:])(),\n",
                "        },\n",
                "        partition_way=PartitionWay.VERTICAL,\n",
                "    )\n",
                "    return v_data\n",
                "\n",
                "\n",
                "v_data = x_to_vdata(x)\n",
                "\n",
                "label_data = FedNdarray(\n",
                "    partitions={alice: alice(lambda: y.values)()},\n",
                "    partition_way=PartitionWay.VERTICAL,\n",
                ")\n",
                "\n",
                "sample_weight = FedNdarray(\n",
                "    partitions={alice: alice(lambda: w.values)()},\n",
                "    partition_way=PartitionWay.VERTICAL,\n",
                ")"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 8,
            "id": "b6b341f8",
            "metadata": {},
            "outputs": [],
            "source": [
                "from secretflow.device.driver import reveal\n",
                "from secretflow.ml.linear.ss_glm.core import get_dist\n",
                "\n",
                "dist = 'Tweedie'\n",
                "ss_glm_power = 1.9\n",
                "\n",
                "\n",
                "class DirectRevealModel:\n",
                "    def __init__(self, model) -> None:\n",
                "        self.model = model\n",
                "\n",
                "    def predict(self, X):\n",
                "        vdata = x_to_vdata(X)\n",
                "        y = self.model.predict(vdata)\n",
                "        return reveal(y).reshape((-1,))\n",
                "\n",
                "    def score(self, X, y, sample_weight=None):\n",
                "        y = y.values\n",
                "        y_pred = self.predict(X)\n",
                "\n",
                "        constant = np.mean(y)\n",
                "        if sample_weight is not None:\n",
                "            constant *= sample_weight.shape[0] / np.sum(sample_weight)\n",
                "\n",
                "        # Missing factor of 2 in deviance cancels out.\n",
                "        deviance = get_dist(dist, 1, ss_glm_power).deviance(y_pred, y, None)\n",
                "        deviance_null = get_dist(dist, 1, ss_glm_power).deviance(\n",
                "            np.average(y, weights=sample_weight) + np.zeros(y.shape), y, None\n",
                "        )\n",
                "        return 1 - (deviance + constant) / (deviance_null + constant)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 9,
            "id": "2352f9b6",
            "metadata": {},
            "outputs": [
                {
                    "name": "stderr",
                    "output_type": "stream",
                    "text": [
                        "\u001b[2m\u001b[36m(_run pid=2434553)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'cuda': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n",
                        "\u001b[2m\u001b[36m(_run pid=2434553)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n",
                        "\u001b[2m\u001b[36m(_run pid=2434553)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INVALID_ARGUMENT: TpuPlatform is not available.\n",
                        "\u001b[2m\u001b[36m(_run pid=2434553)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'plugin': xla_extension has no attributes named get_plugin_device_client. Compile TensorFlow with //tensorflow/compiler/xla/python:enable_plugin_device set to true (defaults to false) to enable this.\n",
                        "\u001b[2m\u001b[36m(_run pid=2434553)\u001b[0m WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n",
                        "\u001b[2m\u001b[36m(_run pid=2435206)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'cuda': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n",
                        "\u001b[2m\u001b[36m(_run pid=2435206)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n",
                        "\u001b[2m\u001b[36m(_run pid=2435206)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INVALID_ARGUMENT: TpuPlatform is not available.\n",
                        "\u001b[2m\u001b[36m(_run pid=2435206)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'plugin': xla_extension has no attributes named get_plugin_device_client. Compile TensorFlow with //tensorflow/compiler/xla/python:enable_plugin_device set to true (defaults to false) to enable this.\n",
                        "\u001b[2m\u001b[36m(_run pid=2435206)\u001b[0m WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n"
                    ]
                },
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "\u001b[2m\u001b[36m(_run pid=2435206)\u001b[0m [2024-02-19 14:19:16.647] [info] [thread_pool.cc:30] Create a fixed thread pool with size 63\n"
                    ]
                },
                {
                    "name": "stderr",
                    "output_type": "stream",
                    "text": [
                        "INFO:jax._src.xla_bridge:Unable to initialize backend 'cuda': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n",
                        "INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n",
                        "INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INVALID_ARGUMENT: TpuPlatform is not available.\n",
                        "INFO:jax._src.xla_bridge:Unable to initialize backend 'plugin': xla_extension has no attributes named get_plugin_device_client. Compile TensorFlow with //tensorflow/compiler/xla/python:enable_plugin_device set to true (defaults to false) to enable this.\n",
                        "WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n",
                        "INFO:root:irls calculating partials...\n",
                        "\u001b[2m\u001b[36m(_run pid=2434836)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'cuda': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n",
                        "\u001b[2m\u001b[36m(_run pid=2434836)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'\n",
                        "\u001b[2m\u001b[36m(_run pid=2434836)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INVALID_ARGUMENT: TpuPlatform is not available.\n",
                        "\u001b[2m\u001b[36m(_run pid=2434836)\u001b[0m INFO:jax._src.xla_bridge:Unable to initialize backend 'plugin': xla_extension has no attributes named get_plugin_device_client. Compile TensorFlow with //tensorflow/compiler/xla/python:enable_plugin_device set to true (defaults to false) to enable this.\n",
                        "\u001b[2m\u001b[36m(_run pid=2434836)\u001b[0m WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n"
                    ]
                },
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "\u001b[2m\u001b[36m(_run pid=2434836)\u001b[0m [2024-02-19 14:19:17.967] [info] [thread_pool.cc:30] Create a fixed thread pool with size 63\n",
                        "\u001b[2m\u001b[36m(_run pid=2434553)\u001b[0m [2024-02-19 14:19:17.942] [info] [thread_pool.cc:30] Create a fixed thread pool with size 63\n",
                        "\u001b[2m\u001b[36m(SPURuntime(device_id=None, party=bob) pid=2440722)\u001b[0m 2024-02-19 14:19:18.332 [info] [thread_pool.cc:ThreadPool:30] Create a fixed thread pool with size 63\n",
                        "\u001b[2m\u001b[36m(SPURuntime(device_id=None, party=alice) pid=2440721)\u001b[0m 2024-02-19 14:19:18.332 [info] [thread_pool.cc:ThreadPool:30] Create a fixed thread pool with size 63\n"
                    ]
                },
                {
                    "name": "stderr",
                    "output_type": "stream",
                    "text": [
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls updating weights...\n",
                        "INFO:root:epoch 1 train times: 12.098223447799683s\n",
                        "INFO:root:epoch 1 validation time cost: 1.5343642234802246\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls updating weights...\n",
                        "INFO:root:epoch 2 train times: 2.2774670124053955s\n",
                        "INFO:root:epoch 2 validation time cost: 0.1729907989501953\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls updating weights...\n",
                        "INFO:root:epoch 3 train times: 2.3008642196655273s\n",
                        "INFO:root:epoch 3 validation time cost: 0.06878900527954102\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls calculating partials...\n",
                        "INFO:root:irls updating weights...\n",
                        "INFO:root:epoch 4 train times: 2.2836296558380127s\n",
                        "INFO:root:epoch 4 validation time cost: 0.0764760971069336\n"
                    ]
                },
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Evaluation of the Tweedie Regressor and SS GLM on target PurePremium\n",
                        "                          TweedieRegressor                SSGLMRegressor                  \n",
                        "subset                               train          test           train              test\n",
                        "metric                                                                                    \n",
                        "D² explained                  1.690000e-02  1.420000e-02      0.05068153       0.048805773\n",
                        "mean Tweedie dev p=1.5000     7.640770e+01  7.640880e+01       86.860509         87.740697\n",
                        "mean Tweedie dev p=1.7000     3.682880e+01  3.692270e+01       39.502311         39.821511\n",
                        "mean Tweedie dev p=1.8000     3.037600e+01  3.045390e+01       31.768926         31.962367\n",
                        "mean Tweedie dev p=1.9000     3.382120e+01  3.387830e+01        34.55947         34.675264\n",
                        "mean Tweedie dev p=1.9900     2.015347e+02  2.015587e+02      201.957253        202.012602\n",
                        "mean Tweedie dev p=1.9990     1.914538e+03  1.914387e+03     1914.937731        1914.81592\n",
                        "mean Tweedie dev p=1.9999     1.904747e+04  1.904558e+04    19047.868483      19046.008127\n",
                        "mean abs. error               2.739865e+02  2.731249e+02      638.732548        703.252033\n",
                        "mean squared error            3.295505e+07  3.213056e+07  62588238.37677  816616971.653716\n"
                    ]
                }
            ],
            "source": [
                "import time\n",
                "from secretflow.ml.linear.ss_glm import SSGLM\n",
                "\n",
                "model = SSGLM(spu)\n",
                "\n",
                "ss_glm_power = 1.9\n",
                "start = time.time()\n",
                "model.fit_irls(\n",
                "    v_data,\n",
                "    label_data,\n",
                "    None,\n",
                "    sample_weight,\n",
                "    n_iter,\n",
                "    'Log',\n",
                "    'Tweedie',\n",
                "    ss_glm_power,\n",
                "    l2_lambda=0.1,\n",
                "    infeed_batch_size_limit=10000000,\n",
                "    fraction_of_validation_set=0.2,\n",
                "    stopping_rounds=2,\n",
                "    stopping_metric='deviance',\n",
                "    stopping_tolerance=0.001,\n",
                ")\n",
                "\n",
                "wrapped_model = DirectRevealModel(model)\n",
                "\n",
                "tweedie_powers = [1.5, 1.7, 1.8, 1.9, 1.99, 1.999, 1.9999]\n",
                "\n",
                "scores_ss_glm_pure_premium = score_estimator(\n",
                "    wrapped_model,\n",
                "    X_train,\n",
                "    X_test,\n",
                "    df_train,\n",
                "    df_test,\n",
                "    target=\"PurePremium\",\n",
                "    weights=\"Exposure\",\n",
                "    tweedie_powers=tweedie_powers,\n",
                ")\n",
                "\n",
                "scores = pd.concat(\n",
                "    [scores_glm_pure_premium, scores_ss_glm_pure_premium],\n",
                "    axis=1,\n",
                "    sort=True,\n",
                "    keys=(\"TweedieRegressor\", \"SSGLMRegressor\"),\n",
                ")\n",
                "print(\"Evaluation of the Tweedie Regressor and SS GLM on target PurePremium\")\n",
                "with pd.option_context(\"display.expand_frame_repr\", False):\n",
                "    print(scores)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 10,
            "id": "75a5c31d",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "subset                                 train          test\n",
                        "observed                        3.917618e+07  1.299546e+07\n",
                        "predicted, tweedie, power=1.90  3.951751e+07  1.325198e+07\n",
                        "predicted, ss glm, power=1.90   1.452159e+08  5.445649e+07\n"
                    ]
                }
            ],
            "source": [
                "res = []\n",
                "for subset_label, x, df in [\n",
                "    (\"train\", X_train, df_train),\n",
                "    (\"test\", X_test, df_test),\n",
                "]:\n",
                "    exposure = df[\"Exposure\"].values\n",
                "    res.append(\n",
                "        {\n",
                "            \"subset\": subset_label,\n",
                "            \"observed\": df[\"ClaimAmount\"].values.sum(),\n",
                "            \"predicted, tweedie, power=%.2f\"\n",
                "            % glm_pure_premium.power: np.sum(exposure * glm_pure_premium.predict(x)),\n",
                "            \"predicted, ss glm, power=%.2f\"\n",
                "            % ss_glm_power: np.sum(exposure * wrapped_model.predict(x)),\n",
                "        }\n",
                "    )\n",
                "\n",
                "print(pd.DataFrame(res).set_index(\"subset\").T)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 11,
            "id": "3b459553",
            "metadata": {},
            "outputs": [
                {
                    "data": {
                        "text/plain": [
                            "[]"
                        ]
                    },
                    "execution_count": 11,
                    "metadata": {},
                    "output_type": "execute_result"
                },
                {
                    "data": {
                        "image/png": "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LCL6Kp9MRdBac+dJKHkyvriIV2zSACWJq1KlCjdu3ABg//79VKlShbJly1K1alXOnj0LRM2wW7duTcOGDSlcuPBznbDmzJlDkSJFqFixIrt27bLcf+XKFXx9ffH29sbPz49r164BUWu/9+vXj8qVK1OgQAG2bdvGW2+9RfHixeNdB378+PF4eXlRsWJFy6ppq1atolKlSpQtW5a6detaGols377d0umtbNmyPH36FIDvvvuOChUq4O3tzahRo14Y48qVK5ZVzeJ7zxs2bKBKlSqUK1eOdu3aJWipVSFEyrRs2TJat27N/fv3E7Rk9RuJjIj609GJJyEmwkxmsqRxfenmtj6xLVle5BrXpT/t27enf//+BAcH07hx4xce79mzJz179uT+/fsv7P6NaXGZEJGRkWzevJm3334bgGLFirFz506cnJzYtGkTI0eOZNmyZUDU9YxHjhzB1dWVokWL8t577+Hk5MSoUaM4dOgQ6dKlo06dOpQtWxaA9957jx49etCjRw9mz57NoEGDLGt5P3r0iD179rBy5UqaN2/Orl27mDlzJhUqVMDf358yZcq8kDVdunQcP36c3377jffff5/Vq1dTvXp19u7di1KKmTNnMn78eCZMmMD333/P1KlTqVatGs+ePcPNzY0NGzZw/vx59u/fj9aa5s2bs2PHDmrWrPnS709c7zlVqlSWbmapU6fm22+/5YcffuDzzz9P8PddCJEyLFq0iG7dulGpUiXWrl1LunTprDugObqIOzhz7MZjAHLYya50SKZF3AghISGUKVOGGzduULx4cerVqwdErZPeo0cPzp8/j1KKiIgIy3P8/PwsP4AlSpTg6tWr3L9/n9q1a1u67HTo0MGypveePXv4888/AejWrdtzM9lmzZqhlMLLy4usWbPi5eUFRC3leuXKlTiLeKdOnSx/DhkyBIi6xrFDhw7cunWL8PBw8ufPD0C1atX44IMP6NKlC61btyZXrlxs2LCBDRs2WD5kPHv2jPPnz8dbxON6z48fP35pNzMhhIjx+++/07VrV6pXr87q1atJkyaN9Qe1zMSdWXYoqv+ET96XN1JxdHS06SJQybKIxzdzdnd3j/fxTJkyvdbMO0bMMfHg4GAaNGjA1KlTGTRoEJ999hl16tRh+fLlXLly5bm9BDEdv+C/dQyLLea1HBwcnntdBweHl75u7OM2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",
                        "text/plain": [
                            "<Figure size 576x576 with 1 Axes>"
                        ]
                    },
                    "metadata": {
                        "needs_background": "light"
                    },
                    "output_type": "display_data"
                }
            ],
            "source": [
                "from sklearn.metrics import auc\n",
                "\n",
                "\n",
                "def lorenz_curve(y_true, y_pred, exposure):\n",
                "    y_true, y_pred = np.asarray(y_true), np.asarray(y_pred)\n",
                "    exposure = np.asarray(exposure)\n",
                "\n",
                "    # order samples by increasing predicted risk:\n",
                "    ranking = np.argsort(y_pred)\n",
                "    ranked_exposure = exposure[ranking]\n",
                "    ranked_pure_premium = y_true[ranking]\n",
                "    cumulated_claim_amount = np.cumsum(ranked_pure_premium * ranked_exposure)\n",
                "    cumulated_claim_amount /= cumulated_claim_amount[-1]\n",
                "    cumulated_samples = np.linspace(0, 1, len(cumulated_claim_amount))\n",
                "    return cumulated_samples, cumulated_claim_amount\n",
                "\n",
                "\n",
                "fig, ax = plt.subplots(figsize=(8, 8))\n",
                "\n",
                "y_pred_total_ss_glm = wrapped_model.predict(X_test).reshape((-1,))\n",
                "y_pred_total = glm_pure_premium.predict(X_test)\n",
                "\n",
                "for label, y_pred in [\n",
                "    (\"Compound Poisson Gamma\", y_pred_total),\n",
                "    (\"Compound Poisson Gamma SS GLM\", y_pred_total_ss_glm),\n",
                "]:\n",
                "    ordered_samples, cum_claims = lorenz_curve(\n",
                "        df_test[\"PurePremium\"], y_pred, df_test[\"Exposure\"]\n",
                "    )\n",
                "    gini = 1 - 2 * auc(ordered_samples, cum_claims)\n",
                "    label += \" (Gini index: {:.3f})\".format(gini)\n",
                "    ax.plot(ordered_samples, cum_claims, linestyle=\"-\", label=label)\n",
                "\n",
                "# Oracle model: y_pred == y_test\n",
                "ordered_samples, cum_claims = lorenz_curve(\n",
                "    df_test[\"PurePremium\"], df_test[\"PurePremium\"], df_test[\"Exposure\"]\n",
                ")\n",
                "gini = 1 - 2 * auc(ordered_samples, cum_claims)\n",
                "label = \"Oracle (Gini index: {:.3f})\".format(gini)\n",
                "ax.plot(ordered_samples, cum_claims, linestyle=\"-.\", color=\"gray\", label=label)\n",
                "\n",
                "# Random baseline\n",
                "ax.plot([0, 1], [0, 1], linestyle=\"--\", color=\"black\", label=\"Random baseline\")\n",
                "ax.set(\n",
                "    title=\"Lorenz Curves\",\n",
                "    xlabel=\"Fraction of policyholders\\n(ordered by model from safest to riskiest)\",\n",
                "    ylabel=\"Fraction of total claim amount\",\n",
                ")\n",
                "ax.legend(loc=\"upper left\")\n",
                "plt.plot()"
            ]
        }
    ],
    "metadata": {
        "kernelspec": {
            "display_name": "Python 3 (ipykernel)",
            "language": "python",
            "name": "python3"
        },
        "language_info": {
            "codemirror_mode": {
                "name": "ipython",
                "version": 3
            },
            "file_extension": ".py",
            "mimetype": "text/x-python",
            "name": "python",
            "nbconvert_exporter": "python",
            "pygments_lexer": "ipython3",
            "version": "3.8.17"
        },
        "vscode": {
            "interpreter": {
                "hash": "de4c945f5346493decaa0ea82289843a7da2415616b96b9f4b104111cc0c19ad"
            }
        }
    },
    "nbformat": 4,
    "nbformat_minor": 5
}
